//
//  TableViewAction.swift
//  Pods-TSKit_Example
//
//  Created by chenyusen on 2018/3/16.
//

import UIKit

public final class TableViewAction: NSObject {
    
    public typealias ActionClosure = (TableCellItem, IndexPath) -> (Bool)
    
    private weak var dataSource: TableViewModel?
    private var cellActionDict: Dictionary = [AnyHashable: ActionClosure]()
    private var cellClassActionDict: Dictionary = [AnyHashable: ActionClosure]()
    
    public var forwardDelegates: NSPointerArray = NSPointerArray.weakObjects()
    public var tableViewCellSelectionStyle: UITableViewCellSelectionStyle = UITableViewCellSelectionStyle.default
    
    public required init(dataSource: TableViewModel,
                targetForward: UITableViewDelegate?) {
        super.init()
        self.dataSource = dataSource
        forwardDelegates.add(targetForward)
    }
}

public extension TableViewAction {
    
    private func shouldForwardSelector(aSelector: Selector) -> Bool {
        let description = protocol_getMethodDescription(UITableViewDelegate.self, aSelector, false, true)
        return description.name != nil && description.types != nil
    }
    
    /// 增加对于forwardDelegate能相应的方法也认为tableaction也可响应
     override public func responds(to aSelector: Selector!) -> Bool {
        if super.responds(to: aSelector) {
            return true
        } else if shouldForwardSelector(aSelector: aSelector) {
            for delegate in forwardDelegates.allObjects {
                if (delegate as AnyObject).responds(to: aSelector) {
                    return true
                }
            }
        }
        return false
        
    }
    
    /// 给它一个机会,让他找个能替代的人去干这件事
    override public func forwardingTarget(for aSelector: Selector!) -> Any? {
        for delegate in forwardDelegates.allObjects {
            if (delegate as AnyObject).responds(to: aSelector) {
                return delegate
            }
        }
        return super.forwardingTarget(for: aSelector)
    }
}

public extension TableViewAction {
    public func tap(cellItem: TableCellItem, action: @escaping ActionClosure) {
        cellActionDict[cellItem.hashValue] = action
    }
    
    public func tap(cellItemClass: TableCellItem.Type, action: @escaping ActionClosure) {
        cellClassActionDict[cellItemClass.hash()] = action
        
    }
}


extension TableViewAction: UITableViewDelegate {
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let cellHeight = dataSource?.cellItem(at: indexPath)?.cellHeight {
            return cellHeight
        }
        return tableView.rowHeight
    }
    
    public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        if let sectionItem = dataSource?.sectionItem(at: section), sectionItem.headerSectionViewClass != nil {
            if let headerHeight = sectionItem.headerHeight {
                return headerHeight
            }
            return tableView.sectionHeaderHeight
        }
        return 0
    }
    
    
    public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if let sectionItem = dataSource?.sectionItem(at: section), sectionItem.footerSectionViewClass != nil {
            if let footerHeight = sectionItem.footerHeight {
                return footerHeight
            }
            return tableView.sectionFooterHeight
        }
        return 0
    }
    
    public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if let sectionItem = dataSource?.sectionItem(at: section), let headerSectionViewClass = sectionItem.headerSectionViewClass {
            return headerFooterView(with: headerSectionViewClass, sectionItem: sectionItem, tableView: tableView)
        }
        return nil
    }
    
    public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if let cellItem = dataSource?.cellItem(at: indexPath) {
            cellItem.currentCell?.selectionStyle = action(cellItem) == nil ? UITableViewCellSelectionStyle.none : tableViewCellSelectionStyle
        }
        
        for delegate in forwardDelegates.allObjects {
            if (delegate as AnyObject).responds(to: #function) {
                (delegate as? UITableViewDelegate)?.tableView!(tableView, willDisplay: cell, forRowAt: indexPath)
            }
        }
    }
}

extension TableViewAction {
    private func headerFooterView(with viewClass:UITableViewHeaderFooterView.Type,
                                  sectionItem: TableSectionItem,
                                  tableView: UITableView) -> UITableViewHeaderFooterView {
        var identifier = "\(viewClass)"
        if let viewClass = viewClass as? TableSectionView.Type {
            if viewClass.shouldAppendSectionItemClassToReuseIdentifier {
                identifier.append("\(sectionItem)")
            }
        }
        var sectionView = tableView.dequeueReusableHeaderFooterView(withIdentifier: identifier)
        if sectionView == nil {
            sectionView = viewClass.init(reuseIdentifier:identifier)
        }
        if let sectionView = sectionView as? TableSectionView {
            sectionView.updateSection(sectionItem: sectionItem)
        }
        return sectionView!
    }
    
    
    public func action(_ cellItem: TableCellItem) -> ActionClosure? {
        
        if let action = cellActionDict[cellItem.hashValue] {
            return action
        } else if let action = cellClassActionDict[type(of: cellItem).hash()] {
            return action
        }
        return nil
    }
    
    
    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        if let cellItem = dataSource?.cellItem(at: indexPath), let action = action(cellItem) {
            let returnValue = action(cellItem, indexPath)
            if returnValue {
                tableView.deselectRow(at: indexPath, animated: true)
            }
        }
    }
}
